    // Copyright (C) 2003  Davis E. King (davis@dlib.net)
    // License: Boost Software License   See LICENSE.txt for the full license.
    #ifndef DLIB_BIGINT_KERNEl_C_
    #define DLIB_BIGINT_KERNEl_C_

    #include "bigint_kernel_abstract.h"
    #include "../algs.h"
    #include "../assert.h"
    #include <iostream>

    namespace dlib
    {

    // ----------------------------------------------------------------------------------------

        template <
            typename bigint_base
            >
        class bigint_kernel_c
        {
            bigint_base data;

            explicit bigint_kernel_c (
                const bigint_base& item
            ) : data(item) {}

        public:

            bigint_kernel_c (
            );

            bigint_kernel_c (
                uint32 value
            );

            bigint_kernel_c (
                const bigint_kernel_c<bigint_base>& item
            );

            ~bigint_kernel_c (
            );

            const bigint_kernel_c<bigint_base> operator+ (
                const bigint_kernel_c<bigint_base>& rhs
            ) const;

            bigint_kernel_c<bigint_base>& operator+= (
                const bigint_kernel_c<bigint_base>& rhs
            );

            const bigint_kernel_c<bigint_base> operator- (
                const bigint_kernel_c<bigint_base>& rhs
            ) const;
            bigint_kernel_c<bigint_base>& operator-= (
                const bigint_kernel_c<bigint_base>& rhs
            );

            const bigint_kernel_c<bigint_base> operator* (
                const bigint_kernel_c<bigint_base>& rhs
            ) const;

            bigint_kernel_c<bigint_base>& operator*= (
                const bigint_kernel_c<bigint_base>& rhs
            );

            const bigint_kernel_c<bigint_base> operator/ (
                const bigint_kernel_c<bigint_base>& rhs
            ) const;

            bigint_kernel_c<bigint_base>& operator/= (
                const bigint_kernel_c<bigint_base>& rhs
            );

            const bigint_kernel_c<bigint_base> operator% (
                const bigint_kernel_c<bigint_base>& rhs
            ) const;

            bigint_kernel_c<bigint_base>& operator%= (
                const bigint_kernel_c<bigint_base>& rhs
            );

            bool operator < (
                const bigint_kernel_c<bigint_base>& rhs
            ) const;

            bool operator == (
                const bigint_kernel_c<bigint_base>& rhs
            ) const;

            bigint_kernel_c<bigint_base>& operator= (
                const bigint_kernel_c<bigint_base>& rhs
            );

            template <typename T>
            friend std::ostream& operator<< (
                std::ostream& out,
                const bigint_kernel_c<T>& rhs
            );

            template <typename T>
            friend std::istream& operator>>  (
                std::istream& in,
                bigint_kernel_c<T>& rhs
            );

            bigint_kernel_c<bigint_base>& operator++ (
            );

            const bigint_kernel_c<bigint_base> operator++ (
                int
            );

            bigint_kernel_c<bigint_base>& operator-- (
            );

            const bigint_kernel_c<bigint_base> operator-- (
                int
            );

            template <typename T>
            friend const bigint_kernel_c<T> operator+  (
                uint16 lhs,
                const bigint_kernel_c<T>& rhs
            );

            template <typename T>
            friend const bigint_kernel_c<T> operator+  (
                const bigint_kernel_c<T>& lhs,
                uint16 rhs
            );

            bigint_kernel_c<bigint_base>& operator+= (
                uint16 rhs
            );

            template <typename T>
            friend const bigint_kernel_c<T> operator-  (
                uint16 lhs,
                const bigint_kernel_c<T>& rhs
            );

            template <typename T>
            friend const bigint_kernel_c<T> operator-  (
                const bigint_kernel_c<T>& lhs,
                uint16 rhs
            );

            bigint_kernel_c<bigint_base>& operator-= (
                uint16 rhs
            );

            template <typename T>
            friend const bigint_kernel_c<T> operator*  (
                uint16 lhs,
                const bigint_kernel_c<T>& rhs
            );

            template <typename T>
            friend const bigint_kernel_c<T> operator*  (
                const bigint_kernel_c<T>& lhs,
                uint16 rhs
            );

            bigint_kernel_c<bigint_base>& operator*= (
                uint16 rhs
            );

            template <typename T>
            friend const bigint_kernel_c<T> operator/  (
                uint16 lhs,
                const bigint_kernel_c<T>& rhs
            );

            template <typename T>
            friend const bigint_kernel_c<T> operator/  (
                const bigint_kernel_c<T>& lhs,
                uint16 rhs
            );

            bigint_kernel_c<bigint_base>& operator/= (
                uint16 rhs
            );

            template <typename T>
            friend const bigint_kernel_c<T> operator%  (
                uint16 lhs,
                const bigint_kernel_c<T>& rhs
            );

            template <typename T>
            friend const bigint_kernel_c<T> operator%  (
                const bigint_kernel_c<T>& lhs,
                uint16 rhs
            );

            bigint_kernel_c<bigint_base>& operator%= (
                uint16 rhs
            );

            template <typename T>
            friend bool operator <  (
                uint16 lhs,
                const bigint_kernel_c<T>& rhs
            );

            template <typename T>
            friend bool operator <  (
                const bigint_kernel_c<T>& lhs,
                uint16 rhs
            );

            template <typename T>
            friend bool operator ==  (
                const bigint_kernel_c<T>& lhs,
                uint16 rhs
            );

            template <typename T>
            friend bool operator ==  (
                uint16 lhs,
                const bigint_kernel_c<T>& rhs
            );

            bigint_kernel_c<bigint_base>& operator= (
                uint16 rhs
            );

            void swap (
                bigint_kernel_c<bigint_base>& item
            ) { data.swap(item.data); }

        };

        template <
            typename bigint_base
            >
        void swap (
            bigint_kernel_c<bigint_base>& a,
            bigint_kernel_c<bigint_base>& b
        ) { a.swap(b); }

    // ----------------------------------------------------------------------------------------

        template <
            typename bigint_base
            >
        inline void serialize (
            const bigint_kernel_c<bigint_base>& item,
            std::ostream& out
        )
        {
            std::ios::fmtflags oldflags = out.flags();
            out << item << ' ';
            out.flags(oldflags);
            if (!out) throw serialization_error("Error serializing object of type bigint_kernel_c");
        }

        template <
            typename bigint_base
            >
        inline void deserialize (
            bigint_kernel_c<bigint_base>& item,
            std::istream& in
        )
        {
            std::ios::fmtflags oldflags = in.flags();
            in >> item;
            in.flags(oldflags);
            if (in.get() != ' ')
            {
                item = 0;
                throw serialization_error("Error deserializing object of type bigint_kernel_c");
            }
        }

    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------
        // member function definitions
    // ----------------------------------------------------------------------------------------
    // ----------------------------------------------------------------------------------------

        template <
            typename bigint_base
            >
        bigint_kernel_c<bigint_base>::
        bigint_kernel_c (
        )
        {}

    // ----------------------------------------------------------------------------------------

        template <
            typename bigint_base
            >
        bigint_kernel_c<bigint_base>::
        bigint_kernel_c (
            uint32 value
        ) :
            data(value)
        {
            // make sure requires clause is not broken
            DLIB_CASSERT( value <= 0xFFFFFFFF ,
                "\tbigint::bigint(uint16)"
                << "\n\t value must be <= (2^32)-1"
                << "\n\tthis:  " << this
                << "\n\tvalue:   " << value
                );
        }

    // ----------------------------------------------------------------------------------------

        template <
            typename bigint_base
            >
        bigint_kernel_c<bigint_base>::
        bigint_kernel_c (
            const bigint_kernel_c<bigint_base>& item
        ) :
            data(item.data)
        {}

    // ----------------------------------------------------------------------------------------

        template <
            typename bigint_base
            >
        bigint_kernel_c<bigint_base>::
        ~bigint_kernel_c (
        )
        {}

    // ----------------------------------------------------------------------------------------

        template <
            typename bigint_base
            >
        const bigint_kernel_c<bigint_base> bigint_kernel_c<bigint_base>::
        operator+ (
            const bigint_kernel_c<bigint_base>& rhs
        ) const
        {
            return bigint_kernel_c<bigint_base>(data + rhs.data);
        }

    // ----------------------------------------------------------------------------------------

        template <
            typename bigint_base
            >
        bigint_kernel_c<bigint_base>& bigint_kernel_c<bigint_base>::
        operator+= (
            const bigint_kernel_c<bigint_base>& rhs
        )
        {
            data += rhs.data;
            return *this;
        }

    // ----------------------------------------------------------------------------------------

        template <
            typename bigint_base
            >
        const bigint_kernel_c<bigint_base> bigint_kernel_c<bigint_base>::
        operator- (
            const bigint_kernel_c<bigint_base>& rhs
        ) const
        {
            // make sure requires clause is not broken
            DLIB_CASSERT( !(*this < rhs),
                "\tconst bigint bigint::operator-(const bigint&)"
                << "\n\t *this should not be less than rhs"
                << "\n\tthis:  " << this
                << "\n\t*this: " << *this
                << "\n\trhs:   " << rhs
                );

            // call the real function
            return bigint_kernel_c<bigint_base>(data-rhs.data);
        }

    // ----------------------------------------------------------------------------------------

        template <
            typename bigint_base
            >
        bigint_kernel_c<bigint_base>& bigint_kernel_c<bigint_base>::
        operator-= (
            const bigint_kernel_c<bigint_base>& rhs
        )
        {
            // make sure requires clause is not broken
            DLIB_CASSERT( !(*this < rhs),
                "\tbigint& bigint::operator-=(const bigint&)"
                << "\n\t *this should not be less than rhs"
                << "\n\tthis:  " << this
                << "\n\t*this: " << *this
                << "\n\trhs:   " << rhs
                );

            // call the real function
            data -= rhs.data;
            return *this;
        }

    // ----------------------------------------------------------------------------------------

        template <
            typename bigint_base
            >
        const bigint_kernel_c<bigint_base> bigint_kernel_c<bigint_base>::
        operator* (
            const bigint_kernel_c<bigint_base>& rhs
        ) const
        {
            return bigint_kernel_c<bigint_base>(data * rhs.data );
        }

    // ----------------------------------------------------------------------------------------

        template <
            typename bigint_base
            >
        bigint_kernel_c<bigint_base>& bigint_kernel_c<bigint_base>::
        operator*= (
            const bigint_kernel_c<bigint_base>& rhs
        )
        {
            data *= rhs.data;
            return *this;
        }

    // ----------------------------------------------------------------------------------------

        template <
            typename bigint_base
            >
        const bigint_kernel_c<bigint_base> bigint_kernel_c<bigint_base>::
        operator/ (
            const bigint_kernel_c<bigint_base>& rhs
        ) const
        {
            //make sure requires clause is not broken
            DLIB_CASSERT( !(rhs == 0),
                "\tconst bigint bigint::operator/(const bigint&)"
                << "\n\t can't divide by zero"
                << "\n\tthis:  " << this
                );

            // call the real function
            return bigint_kernel_c<bigint_base>(data/rhs.data);
        }

    // ----------------------------------------------------------------------------------------

        template <
            typename bigint_base
            >
        bigint_kernel_c<bigint_base>& bigint_kernel_c<bigint_base>::
        operator/= (
            const bigint_kernel_c<bigint_base>& rhs
        )
        {
            // make sure requires clause is not broken
            DLIB_CASSERT( !(rhs == 0),
                "\tbigint& bigint::operator/=(const bigint&)"
                << "\n\t can't divide by zero"
                << "\n\tthis:  " << this
                );

            // call the real function
            data /= rhs.data;
            return *this;
        }

    // ----------------------------------------------------------------------------------------

        template <
            typename bigint_base
            >
        const bigint_kernel_c<bigint_base> bigint_kernel_c<bigint_base>::
        operator% (
            const bigint_kernel_c<bigint_base>& rhs
        ) const
        {
            // make sure requires clause is not broken
            DLIB_CASSERT( !(rhs == 0),
                "\tconst bigint bigint::operator%(const bigint&)"
                << "\n\t can't divide by zero"
                << "\n\tthis:  " << this
                );

            // call the real function
            return bigint_kernel_c<bigint_base>(data%rhs.data);
        }

    // ----------------------------------------------------------------------------------------

        template <
            typename bigint_base
            >
        bigint_kernel_c<bigint_base>& bigint_kernel_c<bigint_base>::
        operator%= (
            const bigint_kernel_c<bigint_base>& rhs
        )
        {
            // make sure requires clause is not broken
            DLIB_CASSERT( !(rhs == 0),
                "\tbigint& bigint::operator%=(const bigint&)"
                << "\n\t can't divide by zero"
                << "\n\tthis:  " << this
                );

            // call the real function
            data %= rhs.data;
            return *this;
        }

    // ----------------------------------------------------------------------------------------

        template <
            typename bigint_base
            >
        bool bigint_kernel_c<bigint_base>::
        operator < (
            const bigint_kernel_c<bigint_base>& rhs
        ) const
        {
            return data < rhs.data;
        }

    // ----------------------------------------------------------------------------------------

        template <
            typename bigint_base
            >
        bool bigint_kernel_c<bigint_base>::
        operator == (
            const bigint_kernel_c<bigint_base>& rhs
        ) const
        {
            return data == rhs.data;
        }

    // ----------------------------------------------------------------------------------------

        template <
            typename bigint_base
            >
        bigint_kernel_c<bigint_base>& bigint_kernel_c<bigint_base>::
        operator= (
            const bigint_kernel_c<bigint_base>& rhs
        )
        {
            data = rhs.data;
            return *this;
        }

    // ----------------------------------------------------------------------------------------

        template <
            typename bigint_base
            >
        std::ostream& operator<< (
            std::ostream& out,
            const bigint_kernel_c<bigint_base>& rhs
        )
        {
            out << rhs.data;
            return out;
        }

    // ----------------------------------------------------------------------------------------

        template <
            typename bigint_base
            >
        std::istream& operator>> (
            std::istream& in,
            bigint_kernel_c<bigint_base>& rhs
        )
        {
            in >> rhs.data;
            return in;
        }

    // ----------------------------------------------------------------------------------------

        template <
            typename bigint_base
            >
        bigint_kernel_c<bigint_base>& bigint_kernel_c<bigint_base>::
        operator++ (
        )
        {
            ++data;
            return *this;
        }

    // ----------------------------------------------------------------------------------------

        template <
            typename bigint_base
            >
        const bigint_kernel_c<bigint_base> bigint_kernel_c<bigint_base>::
        operator++ (
            int
        )
        {
            return bigint_kernel_c<bigint_base>(data++);
        }

    // ----------------------------------------------------------------------------------------

        template <
            typename bigint_base
            >
        bigint_kernel_c<bigint_base>& bigint_kernel_c<bigint_base>::
        operator-- (
        )
        {
            // make sure requires clause is not broken
            DLIB_CASSERT( !(*this == 0),
                "\tbigint& bigint::operator--()"
                << "\n\t *this to subtract from *this it must not be zero to begin with"
                << "\n\tthis:  " << this
                );

            // call the real function
            --data;
            return *this;
        }

    // ----------------------------------------------------------------------------------------

        template <
            typename bigint_base
            >
        const bigint_kernel_c<bigint_base> bigint_kernel_c<bigint_base>::
        operator-- (
            int
        )
        {
            // make sure requires clause is not broken
            DLIB_CASSERT( !(*this == 0),
                "\tconst bigint bigint::operator--(int)"
                << "\n\t *this to subtract from *this it must not be zero to begin with"
                << "\n\tthis:  " << this
                );

            // call the real function
            return bigint_kernel_c<bigint_base>(data--);
        }

    // ----------------------------------------------------------------------------------------

        template <
            typename bigint_base
            >
        const bigint_kernel_c<bigint_base> operator+ (
            uint16 l,
            const bigint_kernel_c<bigint_base>& rhs
        )
        {
            uint32 lhs = l;
            // make sure requires clause is not broken
            DLIB_CASSERT( lhs <= 65535,
                "\tconst bigint operator+(uint16, const bigint&)"
                << "\n\t lhs must be <= 65535"
                << "\n\trhs:   " << rhs
                << "\n\tlhs:   " << lhs
                );

            return bigint_kernel_c<bigint_base>(static_cast<uint16>(lhs)+rhs.data);
        }

    // ----------------------------------------------------------------------------------------

        template <
            typename bigint_base
            >
        const bigint_kernel_c<bigint_base> operator+ (
            const bigint_kernel_c<bigint_base>& lhs,
            uint16 r
        )
        {
            uint32 rhs = r;
            // make sure requires clause is not broken
            DLIB_CASSERT( rhs <= 65535,
                "\tconst bigint operator+(const bigint&, uint16)"
                << "\n\t rhs must be <= 65535"
                << "\n\trhs:   " << rhs
                << "\n\tlhs:   " << lhs
                );

            return bigint_kernel_c<bigint_base>(lhs.data+static_cast<uint16>(rhs));
        }

    // ----------------------------------------------------------------------------------------

        template <
            typename bigint_base
            >
        bigint_kernel_c<bigint_base>& bigint_kernel_c<bigint_base>::
        operator+= (
            uint16 r
        )
        {
            uint32 rhs = r;
            // make sure requires clause is not broken
            DLIB_CASSERT( rhs <= 65535,
                "\tbigint& bigint::operator+=(uint16)"
                << "\n\t rhs must be <= 65535"
                << "\n\tthis:  " << this
                << "\n\t*this: " << *this
                << "\n\trhs:   " << rhs
                );

            data += rhs;
            return *this;
        }

    // ----------------------------------------------------------------------------------------

        template <
            typename bigint_base
            >
        const bigint_kernel_c<bigint_base> operator- (
            uint16 l,
            const bigint_kernel_c<bigint_base>& rhs
        )
        {
            uint32 lhs = l;
            // make sure requires clause is not broken
            DLIB_CASSERT( !(static_cast<uint16>(lhs) < rhs) && lhs <= 65535,
                "\tconst bigint operator-(uint16,const bigint&)"
                << "\n\t lhs must be greater than or equal to rhs and lhs <= 65535"
                << "\n\tlhs:   " << lhs
                << "\n\trhs:   " << rhs
                << "\n\t&lhs:  " << &lhs
                << "\n\t&rhs:  " << &rhs
                );

            // call the real function
            return bigint_kernel_c<bigint_base>(static_cast<uint16>(lhs)-rhs.data);
        }

    // ----------------------------------------------------------------------------------------

        template <
            typename bigint_base
            >
        const bigint_kernel_c<bigint_base> operator- (
            const bigint_kernel_c<bigint_base>& lhs,
            uint16 r
        )
        {
            uint32 rhs = r;
            // make sure requires clause is not broken
            DLIB_CASSERT( !(lhs < static_cast<uint16>(rhs)) && rhs <= 65535,
                "\tconst bigint operator-(const bigint&,uint16)"
                << "\n\t lhs must be greater than or equal to rhs and rhs <= 65535"
                << "\n\tlhs:   " << lhs
                << "\n\trhs:   " << rhs
                << "\n\t&lhs:  " << &lhs
                << "\n\t&rhs:  " << &rhs
                );

            // call the real function
            return bigint_kernel_c<bigint_base>(lhs.data-static_cast<uint16>(rhs));
        }

    // ----------------------------------------------------------------------------------------

        template <
            typename bigint_base
            >
        bigint_kernel_c<bigint_base>& bigint_kernel_c<bigint_base>::
        operator-= (
            uint16 r
        )
        {
            uint32 rhs = r;
            // make sure requires clause is not broken
            DLIB_CASSERT( !(*this < static_cast<uint16>(rhs)) && rhs <= 65535,
                "\tbigint& bigint::operator-=(uint16)"
                << "\n\t *this must not be less than rhs and rhs <= 65535"
                << "\n\tthis:  " << this
                << "\n\t*this: " << *this
                << "\n\trhs:   " << rhs
                );

            // call the real function
            data -= static_cast<uint16>(rhs);
            return *this;
        }

    // ----------------------------------------------------------------------------------------

        template <
            typename bigint_base
            >
        const bigint_kernel_c<bigint_base> operator* (
            uint16 l,
            const bigint_kernel_c<bigint_base>& rhs
        )
        {
            uint32 lhs = l;
            // make sure requires clause is not broken
            DLIB_CASSERT( lhs <= 65535,
                "\tconst bigint operator*(uint16, const bigint&)"
                << "\n\t lhs must be <= 65535"
                << "\n\trhs:   " << rhs
                << "\n\tlhs:   " << lhs
                );

            return bigint_kernel_c<bigint_base>(lhs*rhs.data);
        }

    // ----------------------------------------------------------------------------------------

        template <
            typename bigint_base
            >
        const bigint_kernel_c<bigint_base> operator* (
            const bigint_kernel_c<bigint_base>& lhs,
            uint16 r
        )
        {
            uint32 rhs = r;
            // make sure requires clause is not broken
            DLIB_CASSERT( rhs <= 65535,
                "\tconst bigint operator*(const bigint&, uint16)"
                << "\n\t rhs must be <= 65535"
                << "\n\trhs:   " << rhs
                << "\n\tlhs:   " << lhs
                );

            return bigint_kernel_c<bigint_base>(lhs.data*rhs);
        }

    // ----------------------------------------------------------------------------------------

        template <
            typename bigint_base
            >
        bigint_kernel_c<bigint_base>& bigint_kernel_c<bigint_base>::
        operator*= (
            uint16 r
        )
        {
            uint32 rhs = r;
            // make sure requires clause is not broken
            DLIB_CASSERT( rhs <= 65535,
                "\t bigint bigint::operator*=(uint16)"
                << "\n\t rhs must be <= 65535"
                << "\n\tthis:  " << this
                << "\n\t*this: " << *this
                << "\n\trhs:   " << rhs
                );

            data *= static_cast<uint16>(rhs);
            return *this;
        }

    // ----------------------------------------------------------------------------------------

        template <
            typename bigint_base
            >
        const bigint_kernel_c<bigint_base> operator/ (
            uint16 l,
            const bigint_kernel_c<bigint_base>& rhs
        )
        {
            uint32 lhs = l;
            // make sure requires clause is not broken
            DLIB_CASSERT( !(rhs == 0) && lhs <= 65535,
                "\tconst bigint operator/(uint16,const bigint&)"
                << "\n\t you can't divide by zero and lhs <= 65535"
                << "\n\t&lhs:  " << &lhs
                << "\n\t&rhs:  " << &rhs
                << "\n\tlhs:   " << lhs
                );

            // call the real function
            return bigint_kernel_c<bigint_base>(lhs/rhs.data);
        }

    // ----------------------------------------------------------------------------------------

        template <
            typename bigint_base
            >
        const bigint_kernel_c<bigint_base> operator/ (
            const bigint_kernel_c<bigint_base>& lhs,
            uint16 r
        )
        {
            uint32 rhs = r;
            // make sure requires clause is not broken
            DLIB_CASSERT( !(rhs == 0) && rhs <= 65535,
                "\tconst bigint operator/(const bigint&,uint16)"
                << "\n\t you can't divide by zero and rhs <= 65535"
                << "\n\t&lhs:  " << &lhs
                << "\n\t&rhs:  " << &rhs
                << "\n\trhs:   " << rhs
                );

            // call the real function
            return bigint_kernel_c<bigint_base>(lhs.data/static_cast<uint16>(rhs));
        }

    // ----------------------------------------------------------------------------------------

        template <
            typename bigint_base
            >
        bigint_kernel_c<bigint_base>& bigint_kernel_c<bigint_base>::
        operator/= (
            uint16 rhs
        )
        {
            // make sure requires clause is not broken
            DLIB_CASSERT( !(rhs == 0) && static_cast<uint32>(rhs) <= 65535,
                "\tbigint& bigint::operator/=(uint16)"
                << "\n\t you can't divide by zero and rhs must be <= 65535"
                << "\n\tthis:  " << this
                << "\n\trhs:   " << rhs
                );

            // call the real function
            data /= rhs;
            return *this;
        }

    // ----------------------------------------------------------------------------------------

        template <
            typename bigint_base
            >
        const bigint_kernel_c<bigint_base> operator% (
            uint16 lhs,
            const bigint_kernel_c<bigint_base>& rhs
        )
        {
            // make sure requires clause is not broken
            DLIB_CASSERT( !(rhs == 0) && static_cast<uint32>(lhs) <= 65535,
                "\tconst bigint operator%(uint16,const bigint&)"
                << "\n\t you can't divide by zero and lhs must be <= 65535"
                << "\n\t&lhs:  " << &lhs
                << "\n\t&rhs:  " << &rhs
                << "\n\tlhs:   " << lhs
                );

            // call the real function
            return bigint_kernel_c<bigint_base>(lhs%rhs.data);
        }

    // ----------------------------------------------------------------------------------------

        template <
            typename bigint_base
            >
        const bigint_kernel_c<bigint_base> operator% (
            const bigint_kernel_c<bigint_base>& lhs,
            uint16 r
        )
        {
            uint32 rhs = r;
            // make sure requires clause is not broken
            DLIB_CASSERT( !(rhs == 0) && rhs <= 65535,
                "\tconst bigint operator%(const bigint&,uint16)"
                << "\n\t you can't divide by zero and rhs must be <= 65535"
                << "\n\t&lhs:  " << &lhs
                << "\n\t&rhs:  " << &rhs
                << "\n\trhs:   " << rhs
                );

            // call the real function
            return bigint_kernel_c<bigint_base>(lhs.data%static_cast<uint16>(rhs));
        }

    // ----------------------------------------------------------------------------------------

        template <
            typename bigint_base
            >
        bigint_kernel_c<bigint_base>& bigint_kernel_c<bigint_base>::
        operator%= (
            uint16 r
        )
        {

            uint32 rhs = r;
            // make sure requires clause is not broken
            DLIB_CASSERT( !(rhs == 0) && rhs <= 65535,
                "\tbigint& bigint::operator%=(uint16)"
                << "\n\t you can't divide by zero and rhs must be <= 65535"
                << "\n\tthis:  " << this
                << "\n\trhs:   " << rhs
                );

            // call the real function
            data %= rhs;
            return *this;
        }

    // ----------------------------------------------------------------------------------------

        template <
            typename bigint_base
            >
        bool operator < (
            uint16 l,
            const bigint_kernel_c<bigint_base>& rhs
        )
        {
            uint32 lhs = l;
            // make sure requires clause is not broken
            DLIB_CASSERT( lhs <= 65535,
                "\tbool operator<(uint16, const bigint&)"
                << "\n\t lhs must be <= 65535"
                << "\n\trhs:   " << rhs
                << "\n\tlhs:   " << lhs
                );

            return static_cast<uint16>(lhs) < rhs.data;
        }

    // ----------------------------------------------------------------------------------------

        template <
            typename bigint_base
            >
        bool operator < (
            const bigint_kernel_c<bigint_base>& lhs,
            uint16 r
        )
        {
            uint32 rhs = r;
            // make sure requires clause is not broken
            DLIB_CASSERT( rhs <= 65535,
                "\tbool operator<(const bigint&, uint16)"
                << "\n\t rhs must be <= 65535"
                << "\n\trhs:   " << rhs
                << "\n\tlhs:   " << lhs
                );

            return lhs.data < static_cast<uint16>(rhs);
        }

    // ----------------------------------------------------------------------------------------

        template <
            typename bigint_base
            >
        bool operator == (
            const bigint_kernel_c<bigint_base>& lhs,
            uint16 r
        )
        {
            uint32 rhs = r;
            // make sure requires clause is not broken
            DLIB_CASSERT( rhs <= 65535,
                "\tbool operator==(const bigint&, uint16)"
                << "\n\t rhs must be <= 65535"
                << "\n\trhs:   " << rhs
                << "\n\tlhs:   " << lhs
                );

            return lhs.data == static_cast<uint16>(rhs);
        }

    // ----------------------------------------------------------------------------------------

        template <
            typename bigint_base
            >
        bool operator == (
            uint16 l,
            const bigint_kernel_c<bigint_base>& rhs
        )
        {
            uint32 lhs = l;
            // make sure requires clause is not broken
            DLIB_CASSERT( lhs <= 65535,
                "\tbool operator==(uint16, const bigint&)"
                << "\n\t lhs must be <= 65535"
                << "\n\trhs:   " << rhs
                << "\n\tlhs:   " << lhs
                );

            return static_cast<uint16>(lhs) == rhs.data;
        }

    // ----------------------------------------------------------------------------------------

        template <
            typename bigint_base
            >
        bigint_kernel_c<bigint_base>& bigint_kernel_c<bigint_base>::
        operator= (
            uint16 r
        )
        {
            uint32 rhs = r;
            // make sure requires clause is not broken
            DLIB_CASSERT( rhs <= 65535,
                "\tbigint bigint::operator=(uint16)"
                << "\n\t rhs must be <= 65535"
                << "\n\t*this:  " << *this
                << "\n\tthis:   " << this
                << "\n\tlhs:    " << rhs
                );

            data = static_cast<uint16>(rhs);
            return *this;
        }

    // ----------------------------------------------------------------------------------------

        template < typename bigint_base >
        inline bool operator>  (const bigint_kernel_c<bigint_base>& a, const bigint_kernel_c<bigint_base>& b) { return b < a; }
        template < typename bigint_base >
        inline bool operator!= (const bigint_kernel_c<bigint_base>& a, const bigint_kernel_c<bigint_base>& b) { return !(a == b); }
        template < typename bigint_base >
        inline bool operator<= (const bigint_kernel_c<bigint_base>& a, const bigint_kernel_c<bigint_base>& b) { return !(b < a); }
        template < typename bigint_base >
        inline bool operator>= (const bigint_kernel_c<bigint_base>& a, const bigint_kernel_c<bigint_base>& b) { return !(a < b); }

    // ----------------------------------------------------------------------------------------

    }

    #endif // DLIB_BIGINT_KERNEl_C_